package arithmetic.thread.bolckqueen;

import java.util.ArrayList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import lombok.extern.slf4j.Slf4j;
import utils.ValidUtils;

/**
 * 我的阻塞队列3, LockSupport写法 condition写法 await,  signal  jdk里的ArrayBlockQueen实现方法
 * @author jiangfeng on 2022/4/9
 */
public class MyBlockQueen3<T> implements  MyBlockQueenInterface<T>{


    public static Logger log = LoggerFactory.getLogger(ValidUtils.class);
    private final ArrayList<T> arrays;
    private final Integer maxLength;
    private ReentrantLock lock = new ReentrantLock();
    // 用于条件唤醒 jdk也是这样实现的
    //private Condition condition = lock.newCondition();
    private Condition consumerCondition = lock.newCondition();
    private Condition productorCondition = lock.newCondition();


    /**
     * 初始化
     * @param maxLength
     */
    public MyBlockQueen3(int maxLength) {
        this.maxLength = maxLength;
        arrays = new ArrayList<T>(maxLength);
    }

    @Override
    // 关键点在于如何阻塞??,
    public void put(T t) {
        lock.lock();
        try {
            // 最大数量需要阻塞
            while (arrays.size() == maxLength) {
                // 进入休眠,唤醒别的线程
                try {
                    productorCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            arrays.add(t);
            log.info("{},add: {}", Thread.currentThread().getName(), t);
            // 添加完了可以唤醒,消费者了
            consumerCondition.signal();
            //productorCondition.signal(); // 错误写法,没有唤醒生产者.
        }finally {
            lock.unlock();
        }
    }
    
    @Override
    public T take() {

        lock.lock();
        try {
            // 没有元素需要阻塞
            while (arrays.size() == 0) {
                // 进入休眠
                try {
                    consumerCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            T remove = arrays.remove(arrays.size() - 1);
            log.info("{},take: {}", Thread.currentThread().getName(), remove);
            // 消费完了 可以唤醒生产者继续了.
            productorCondition.signal();
            // 唤醒别的线程
            return remove;
        }finally {
            lock.unlock();
        }

    }





}
